package com.lcm.weam.config;

import com.lcm.weam.shiro.UserRealm;
import com.lcm.weam.shiro.WeamWebSessionManager;
import org.apache.shiro.authc.AbstractAuthenticator;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class ShiroConfiguration {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private String port;
    @Value("${spring.redis.timeout}")
    private String timeout;

    //配置自定义realm
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

/*    @Bean
    public MobileRealm mobileRealm(){
        return new MobileRealm();
    }*/

    @Bean
    public AbstractAuthenticator abstractAuthenticator(UserRealm userRealm){
        // 自定义模块化认证器，用于解决多realm抛出异常问题
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        // 认证策略：AtLeastOneSuccessfulStrategy(默认)，AllSuccessfulStrategy，FirstSuccessfulStrategy
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        // 加入realms
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm);
//        realms.add(mobileRealm);
        authenticator.setRealms(realms);
        return authenticator;
    }


    //配置安全管理器
    @Bean
    public SecurityManager securityManager(UserRealm userRealm, AbstractAuthenticator abstractAuthenticator){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realms
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm);
//        realms.add(mobileRealm);
        securityManager.setRealms(realms);
        // 自定义缓存实现，可以使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理，可以使用redis
        securityManager.setSessionManager(sessionManager());
        // 注入记住我管理器
        securityManager.setRememberMeManager(rememberMeManager());
        // 认证器
        securityManager.setAuthenticator(abstractAuthenticator);
        return securityManager;
    }

    //最重要的配置项，配置过滤、跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        bean.setLoginUrl("/anon/autherror?code=1");
        bean.setUnauthorizedUrl("/anon/autherror?code=2");
        bean.setFilterChainDefinitionMap(FilterChainDefinitionMapBuilder.build());
        return bean;
    }

    //配置注解支持 start
    //@RequiresPermissions(value="user-update")
    //@RequiresRoles(value="项目负责人")
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }
    //配置注解支持 end

    //redis实现会话管理配置 start
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host+":"+port);
        redisManager.setTimeout(Integer.parseInt(timeout));
        return redisManager;
    }
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setPrincipalIdFieldName("uid");
        return redisCacheManager;
    }
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }
    public SessionManager sessionManager() {
        //使用自定义sessionManager(但未重写任何方法)
        WeamWebSessionManager sessionManager = new WeamWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }
    //redis实现会话管理配置 end

    //记住我 功能配置 start
    //cookie对象
    public SimpleCookie rememberMeCookie(){
        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //cookie生效时间7天,单位秒;
        simpleCookie.setMaxAge(604800);
        return simpleCookie;
    }
    //cookie管理对象 记住我功能
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        // cookieRememberMeManager.setCipherKey用来设置加密的Key,参数类型byte[],允许的byte数组长度为16
        // 为何是16？https://www.jianshu.com/p/960e5a23a523
        cookieRememberMeManager.setCipherKey("WEAM_COOKIE_CODE".getBytes());
        return cookieRememberMeManager;
    }
    //记住我 功能配置 end
}
